#pragma once
#ifndef LIGHTING_LIGHTSERVER_H
#define LIGHTING_LIGHTSERVER_H
//------------------------------------------------------------------------------
/**
    @class Lighting::LightServer
  
    The LightServer controls the global aspects of dynamic lighting. It
    sorts the light sources of a stage which passed the visibility test
    by "importance", communicates the lighting parameters to the shader 
    system and controls shadow map generation.
    
    (C) 2007 Radon Labs GmbH
*/
#include "core/refcounted.h"
#include "core/singleton.h"
#include "graphics/cameraentity.h"
#include "graphics/modelentity.h"
#include "lighting/globallightentity.h"
#include "resources/managedtexture.h"
#include "coregraphics/shadervariable.h"
#include "coregraphics/shaderfeature.h"

//------------------------------------------------------------------------------
namespace Lighting
{
class LightServer : public Core::RefCounted
{
    DeclareClass(LightServer);
    DeclareSingleton(LightServer);
public:
    /// constructor
    LightServer();
    /// destructor
    virtual ~LightServer();    

    /// open the light server
    void Open();
    /// close the light server
    void Close();
    /// return true if light server is open
    bool IsOpen() const;

    /// begin lighting frame
    void BeginFrame(const Ptr<Graphics::CameraEntity>& cameraEntity);
    /// begin attaching visible light sources
    void BeginAttachVisibleLights();
    /// attach a visible light source
    void AttachVisibleLight(const Ptr<AbstractLightEntity>& lightEntity);
    /// end attaching visible light sources
    void EndAttachVisibleLights();
    /// apply lighting parameters for a visible model entity 
    void ApplyModelEntityLights(const Ptr<Graphics::ModelEntity>& modelEntity);
    /// end lighting frame
    void EndFrame();

private:
    static const SizeT MaxLights = 4;
    
    bool isOpen;
    bool inBeginFrame;
    bool inBeginAttach;
    Ptr<Graphics::CameraEntity> cameraEntity;
    Ptr<GlobalLightEntity> globalLightEntity;
    Util::Array<Ptr<AbstractLightEntity>> visibleLightEntities;
    Util::FixedArray<CoreGraphics::ShaderFeature::Mask> shdFeatureMasks;
    CoreGraphics::ShaderFeature::Mask allLightsFeatureMask;

    // local light parameters
    Math::point lightPos[MaxLights];
    float lightInvRange[MaxLights];
    Math::matrix44 lightProjTransform[MaxLights];
    Math::float4 lightColor[MaxLights];
    Math::float4 lightProjMapUvOffset[MaxLights];
    LightType::Code lightType[MaxLights];
    bool lightCastShadows[MaxLights];
    Math::float4 lightShadowBufferUvOffset[MaxLights];
    Ptr<Resources::ManagedTexture> lightProjMap; 

    // shared shader parameters
    Ptr<CoreGraphics::ShaderVariable> shdGlobalLightDir;
    Ptr<CoreGraphics::ShaderVariable> shdGlobalLightColor;
    Ptr<CoreGraphics::ShaderVariable> shdGlobalBackLightColor;
    Ptr<CoreGraphics::ShaderVariable> shdGlobalLightCastShadows;
    Ptr<CoreGraphics::ShaderVariable> shdNumLights;
    Ptr<CoreGraphics::ShaderVariable> shdLightPos;
    Ptr<CoreGraphics::ShaderVariable> shdLightInvRange;
    Ptr<CoreGraphics::ShaderVariable> shdLightProjTransform;
    Ptr<CoreGraphics::ShaderVariable> shdLightColor;
    Ptr<CoreGraphics::ShaderVariable> shdLightProjMapUvOffset;
    Ptr<CoreGraphics::ShaderVariable> shdLightType;
    Ptr<CoreGraphics::ShaderVariable> shdLightCastShadows;
    Ptr<CoreGraphics::ShaderVariable> shdLightShadowBufferUvOffset;
    Ptr<CoreGraphics::ShaderVariable> shdLightShadowBuffer;
    Ptr<CoreGraphics::ShaderVariable> shdLightShadowBufferSize;
    Ptr<CoreGraphics::ShaderVariable> shdLightProjMap;
};

//------------------------------------------------------------------------------
/**
*/
inline bool
LightServer::IsOpen() const
{
    return this->isOpen;
}

} // namespace Lighting
//------------------------------------------------------------------------------
#endif
